<?php

/***  DOCUMENTATION LAYER

CEO Access Control Extension

Name: CeoAce
Last Update: Sep 2007
Author: Tom at klenwell@gmail.com
License: GNU GPL (http://www.opensource.org/licenses/gpl-license.html)

DESCRIPTION
  Class controls page access and login form

METHODS
  MAGIC
  CeoAce($debug=0, $oid=null)    *php 4 constructor*
  __construct($debug, $oid)          *php 5 constructor*
  __destruct()  
  
  PUBLIC
  restrict_access_to($level)
  restrict_access_below($level)
  restrict_access_within($ARRAY)
  redirect_to_login($)
    
  print_d($message, $color='c33')
  print_r()
  dump()
  
  PRIVATE
  _is_granted_access($access_url)
  _get_visitor_data()
  _get_member_session_data()
  
  _set_session_data()
  _get_session_data()
  _has_session_data()
  _set_filename()
  _set_dirpath()
  
USAGE
  $Ceo->load_ext('ace');
  $Ceo->Ace->restrict_page($int);

NOTES
  This class must be used in conjunction with a database (where login information
  is stored and retrieved).  The login form field `login_handle` serves as the search
  term for the indexed `handle` column in the database.
  
  Pages are restricted based on `level` settings.  A user must also a `level`
  setting that is active (1).  The STATUS array can be used to define different
  status values as active (1) or inactive (0).
  
  The USER array property stores various user values.  These include:
  
    is_logged_in    - 0/1 (0 by default)
    level           - int value against which page access is defined
    status          - an int value that is then converted to 1 or 0 via the STATUS array
    login_uts       - time user logged in (used to expire session after period of time)
    
  A database object -- for retrieving user data -- can be added to a Ace object
  via the inject_dbo as application of the concept of dependency injection
  (http://en.wikipedia.org/wiki/Dependency_injection).  Within the Ceo framework,
  the driver called when this extension is loaded inject the Dbo automatically.
  
  For password security on non-SSL site, the technique outlined here is 
  used: http://tinyurl.com/3dtcdr.  This takes advantage of the md5 class
  for js by Paul A. Johnson: http://pajhome.org.uk/crypt/md5/md5.js
  
  For additional information on issues relevant to this class, see this Usenet
  discussion thread:
  
  http://groups.google.com/group/comp.lang.php/browse_frm/thread/c5960aa0afac2621/4993d290eb78f811

______________________________________________________________________________*/

// Load File of Base Class
$base_fname = 'parent.class.php';
#$base_dirpath = dirname(__FILE__) . DIRECTORY_SEPARATOR;
#require_once($base_dirpath . $base_fname);


// Class
/*____________________________________________________________________________*/
class CeoAce
{
/* PUBLIC PROPERTIES */
var $debug = 0;
var $class_name = __CLASS__;
var $oid = '';
var $DS = DIRECTORY_SEPARATOR;

// control arrays
var $LEVEL = array();         // assoc array: id => int (valid level settings)
var $STATUS = array();        // assoc array: code => 0/1 (validity)
var $USER = array();          // user data
var $PROMPT_MSG = array();    // prompt codes
var $LOCKOUT_MSG = array();   // lockout codes

// ace settings
var $session_length = 1800;         // session length (in seconds)

// db settings
var $Dbo = 0;                       // database object
var $root_table = 'ceo_root';
var $status_table = 'ceo_status';
var $hash_salt = '';

// login form settings
var $max_login_attempts = 5;
var $login_url = '';          // url where login redirects are sent; if empty, use local mod (ctrl/tpl)
var $login_action = '';       // where login form post request is direct; empty returns to same url
var $signup_url = '';         // if !empty, adds a link to a signup page to form
var $login_ctrl = '';         // ctrl file (if login_url is empty)
var $login_tpl = '';          // tpl file
var $uh_fn = 'login_name';    // user handler field name
var $pw_fn = 'login_pw';      // password field name
var $sss_fn = 'ace_ss_salt';  // server side salt field name
var $nnc_fn = 'login_nonce';  // login challenge/nonce field name
var $logout_bx_img = 'tba';   // logout bx image
var $noscript_flag = 'ace_noscript';  // no script flag (include as hidden input in form to cue non-hashing form)

// external files
var $js_md5_src = 'http://klenwell.googlecode.com/svn/trunk/JS/os_library/paj.md5.js';
var $favicon_lock = 'http://kwimgs.googlepages.com/favlock.ico';   // default locked icon
var $favicon_nojs = 'http://kwimgs.googlepages.com/favnojs.ico';   // default js-disabled icon


/* PRIVATE PROPERTIES */
var $_req_level = 1024;                                            // level required to view page
var $_logout_bx_name = 'ace_logout_bx';
var $_filename = '';
var $_dirpath = '';


/* ** MAGIC METHODS ** */
// php4 constructor
function CeoAce($debug=0, $oid=null)
{
  $this->__construct($debug, $oid);
  register_shutdown_function( array($this, '__destruct') );
}
// END constructor

// php5 constructor
function __construct($debug=0, $oid=null)
{
  // default
  $this->debug = $debug;
  $this->oid = ( empty($oid) ) ? $this->class_name : $oid;
  $this->_set_filename();
  $this->_set_dirpath();
  
  // set control array values
  $this->STATUS = array( 0 => 0, 1 => 1 );
  $this->LEVEL = array( 'admin' => 8, 'member' => 2, 'guest' => 1, 'anonymous' => 0, 'troll' => -1 );
  $this->_get_ace_codes();
  
  // initialize USER properties 
  $this->USER['is_logged_in'] = 0;
  
  // initialize session vars
  if ( !session_id() ) session_start(); 
  $this->_get_user_session_data();
  if ( !isset($_SESSION[$this->oid]['PROMPT']) ) $_SESSION[$this->oid]['PROMPT'] = array();
  if ( !isset($_SESSION[$this->oid]['status']) ) $_SESSION[$this->oid]['status'] = '';
  
  // login form settings
  $this->login_ctrl = $this->_dirpath . 'login.ctrl.php';
  $this->login_tpl = $this->_dirpath . 'login.tpl.php';
  $this->md5_js_src = 'http://klenwell.googlecode.com/svn/trunk/JS/kwyption/md5.js';
  $this->hash_salt = md5($this->oid);
  
  // debug
  if ( $this->debug ) $this->print_d('debugging is active for oid ' . $this->oid);
  if ( $this->debug ) $this->print_d('constructor complete for class ' . __CLASS__);
}
// END constructor

// destructor
function __destruct()
{
  if ( $this->debug ) $this->print_d("destroying class {$this->class_name} (oid: {$this->oid})");
}
// END destructor



/* ** PUBLIC METHODS ** */
// method: restrict page - admit (do nothing) or restrict (redirect)
function restrict_access_below($req_level, $redirect_url=null)
{
  $admit = 0;   // return
  if ( $this->debug ) $this->print_d("access below level [$req_level] restricted for this page");
  
  // decision tree  
    // too many login attempts
    if ( $this->_get_login_attempts() > $this->max_login_attempts )
    {
      if ( $this->debug ) $this->print_d('too many login attempts -- locking out', 'red');
      $this->_lockout_code = $this->LOCKOUT_MSG['attempts'];
      $this->_lockout();
      return 0; 
    }
  
    // not logged in -> redirect to login
    if ( !$this->USER['is_logged_in'] ) 
    {
      $this->_req_level = $req_level;
      $this->_push_login_prompt($this->PROMPT_MSG['protected']);
      $this->_update_status_message($this->STATUS_MSG['not_logged_in']);
      
      // redirect
      $this->_redirect_to_login();
    }
    
    // logged in, inactive -> lockout
    elseif ( !$this->is_user_active() ) 
    {
      if ( $this->debug ) $this->print_d('inactive status -- lock out', 'red');
      $this->_lockout_code = $this->LOCKOUT_MSG['inactive'];
      $this->_lockout();
      return 0;  
    }
    
    // logged in, sub-level -> lockout
    elseif ( $this->USER['level'] < $req_level ) 
    {
      if ( $this->debug ) $this->print_d('level not authorized -- lock out', 'red');
      $this->_lockout_code = $this->LOCKOUT_MSG['level'];
      $this->_lockout();
      return 0;
    } 
    
    // is session expired
    elseif ( $this->is_session_expired() )
    {
      if ( $this->debug ) $this->print_d('session expired -- log out', 'red');
      $this->_push_login_prompt($this->PROMPT_MSG['session_expired']);
      $this->logout();
    }
    
    // logged in, level and active -> return 0
    else
    {
      if ( $this->debug ) $this->print_d('user granted access', 'green');
      $this->_reset_login_prompt();
      $this->_update_status_message($this->STATUS_MSG['logged_in']);
      return 1; 
    }

  return 0;
}
// END method



// method: attempt login (check db, compare level, status)
function attempt_login($handle='', $client_pw='')
{
  $admit = 0;   // return
  if ( $this->debug ) $this->print_d("login attempt for handle [$handle]");
  
  $nonce = $this->get_login_nonce();
  $_FLAG['client_hashing'] = ( !empty($_POST[$this->noscript_flag]) ) ? 0 : 1;
  
  // sanity checks
  if ( is_null($this->_req_level) ) { trigger_error('req level is null', E_USER_ERROR); return 0; }
  if ( empty($handle) ) { trigger_error('POST user handle is empty', E_USER_ERROR); return 0; }
  if ( empty($client_pw) ) { trigger_error('POST user password is empty', E_USER_ERROR); return 0; }
  
  // count login attempt (must be right here!)
  $this->_count_login_attempt();
  
  // select member data from db
  if ( !$DB_DATA = $this->_select_member_data($handle) )
  {
    $this->_push_login_prompt($this->PROMPT_MSG['user_not_found']);
    return 0;
  }

  // compare passwords
  $db_hash_input = $DB_DATA['password'] . $nonce;
  $db_password = ( $_FLAG['client_hashing'] ) ? md5($db_hash_input) : $DB_DATA['password'];
  $form_password = ( $_FLAG['client_hashing'] ) ? $client_pw : $this->_hash($client_pw);
  $logged_in = ( $form_password == $db_password ) ? 1 : 0;
  
  // debug (with all the hashing, values must be tracked carefully)
  if ( $this->debug ) $this->print_d("hash flag {$_FLAG['client_hashing']} : pt [$db_hash_input]", 'aqua');
  if ( $this->debug ) $this->print_d("$logged_in = $form_password == $db_password");
  
  // unset the nonce
  $this->_unset_login_nonce();
  
  // failed to log in
  if ( !$logged_in )
  {
    if ( $this->debug ) $this->print_d("login failed for handle [$handle]", 'red');
    $this->_push_login_prompt($this->PROMPT_MSG['pw_not_found']);
    return 0;
  }
  
  if ( $this->debug ) $this->print_d("login succeeded for handle [$handle]", 'green');
  
  // reset attempt count
  $this->_reset_login_attempts();
  
  // logged in: store user data to session
  $this->USER['is_logged_in'] = 1;
  $this->USER['uid'] = $DB_DATA['uid'];
  $this->USER['handle'] = $handle;
  $this->USER['level'] = $DB_DATA['level'];
  $this->USER['status'] = $DB_DATA['status'];
  $this->USER['login_uts'] = time();
  $this->_set_user_session_data();
  $this->_update_status_message($this->STATUS_MSG['logged_in']);

  // redirect back to page (to now check credentials) with flag to preserve current nonce
  $this->_set_session_value('preserve_nonce',1);  
  $this->_redirect_to_url($this->_get_session_value('gateway'));

  return 1;
}
// END method



// method: is user active
function is_user_active()
{
  $is_active = 0;
  if ( $this->debug ) $this->print_d('checking user status');
  
  // sanity check
  if ( !isset($this->USER) || !isset($this->USER['status']) )
  {
    trigger_error('user status not set', E_USER_WARNING);
    return 0;
  }
  
  // is valid status setting?
  if ( !isset($this->STATUS[$this->USER['status']]) )
  {
    trigger_error("invalid status setting [{$this->USER['status']}] -- check STATUS array", E_USER_WARNING);
    return 0;
  }
  
  return $this->STATUS[$this->USER['status']];
}
// END method



// method: bind a database object (see note above)
function bind_dbo(&$Dbo)
{
  if ( $this->debug ) $this->print_d('binding a database object to this Ace object');
  
  // sanity check
  if ( !is_object($Dbo) )
  {
    trigger_error('argument must be database object', E_USER_WARNING);
    return 0;
  }
  
  if ( is_object($this->Dbo) )
  {
    trigger_error('this Ace class already has a database object');
    return;
  }
  
  $this->Dbo = $Dbo; 
  return;
}
// END method



// method: reset user
function logout()
{
  $this->_update_status_message($this->STATUS_MSG['not_logged_in']);
  $this->_push_login_prompt($this->PROMPT_MSG['logged_out']);
  $this->USER['is_logged_in'] = 0;
  $this->_reset_user();
  $this->_set_user_session_data();
  $this->_redirect_to_url($this->_get_url_self());  // redirect to self (now logged out)
  return;
}
// END method



// method: has the session expired?
function is_session_expired()
{
  $is_expired = 0;
  
  $session_age = time() - $this->USER['login_uts'];
  if ( $session_age > $this->session_length ) $is_expired = 1;
  
  if ( $this->debug ) $this->print_d("checking to see if ace session expired [age | limit | status] : $session_age | {$this->session_length} | $is_expired");
  return $is_expired;
}
// END method



// method: dev
function get_login_nonce()
{
  $nonce = '';      // return
  if ( !$this->_get_session_value($this->nnc_fn) )  $this->_set_login_nonce();
  $nonce = $this->_get_session_value($this->nnc_fn);
  if ( $this->debug ) $this->print_d("getting nonce: $nonce");
  return $nonce;
}
// END method



// method: return prompt string
function print_prompt_block($num_msg=4)
{
  $html = '';   // return
  $list = '';
  $PROMPTS = $this->_get_login_prompt();
  
  if ( empty($PROMPTS) ) return '';
  
  while ( $num_msg > 0 && !empty($PROMPTS) )
  {
    $msg = array_pop($PROMPTS);
    $list .= "<li>$msg</li>\n";
    $num_msg--;
  }

  if ( !empty($list) ) $html = "<ul class=\"ace_prompt_list\">\n{$list}\n</ul>";
  $this->_reset_login_prompt();
  return $html;
}
// END method



// method: print status block
function print_status_block($logout_bx='form')
{
  $html = '';     // return
  
  $status = $this->_get_status_message();
  if ( empty($status) ) return '';
  
  // if logged in, logout button type (image or form)
  if ( $this->USER['is_logged_in'] )
  {
    $bx = $this->get_logout_button($logout_bx);
  }
  
  $html = "<div class=\"ace_status\">{$status} {$bx}</div>";
  return $html;
}
// END method



// method: print logout button (only if logged in)
function get_logout_button($bx_type='form')
{
  $html = '';
  
   // handle logout request here (since a request should necessarily return here)
  #die($this->print_r($_POST));
  if ( $_POST[$this->_logout_bx_name] ) $this->logout();

  // button types
  $input_bx = '<input type="submit" name="push_'.$this->_logout_bx_name.'" value="logout" />';
  $img_bx = '<input type="image" src="'.$this->logout_bx_img.'" alt="logout button" name="push_'.$this->_logout_bx_name.'" value="logout" />';
  $hidden_bx = '<input type="hidden" name="'.$this->_logout_bx_name.'" value="1" />';
  
  // set button
  $bx = ( $bx_type == 'img' ) ? $img_bx : $input_bx;
  
  $html = <<<HTML
<form id="ace_logout_button" name="ace_logout_button" method="post" action="{$_SERVER['PHP_SELF']}">
{$bx} {$hidden_bx}
</form>
  
HTML;

  return $html;
}



// method: dev
function dev()
{
  $this->print_d(__FUNCTION__ . ' in dev');
  return;
}
// END method



// method: print_d
function print_d($message, $color='#c33')
{
  $_D = debug_backtrace();
  $f = basename($_D[0]['file']);
  $l = $_D[0]['line'];
  $loc = "{$f}:{$l}";
  $out = "<div style='line-height:1.5em; font-family:monospace; color:$color;'>$message <span style='color:#666;'>[$loc]</span></div>";
  $this->_DBG[] = "$loc -> " . strip_tags($message);
  echo $out;
  return;
}
// END method

// method: print_r
function print_r($Mixed)
{
  $return = htmlspecialchars(print_r($Mixed, 1));
  $return = "<pre>$return</pre>";
  return $return;
}
// END method

// method: dump
function dump()
{
  echo $this->print_r($this);
  return;
}
// END method



/* ** PRIVATE METHODS ** */
// method: select member data from db
function _select_member_data($handle)
{
  $DATA = 0;    // return
  if ( $this->debug ) $this->print_d("selecting member data from DB for handle [$handle]");
  
  $sql = <<<SQL
  
SELECT t1.uid, t1.password, t2.level, t2.status
FROM ace_root AS t1
LEFT JOIN ace_status AS t2 ON t2.root_uid = t1.uid
WHERE t1.handle = ?
  
SQL;

  // data bind array
  $_DATA_BIND = array( $handle );

  // execute
  if ( !$ResultSet = $this->Dbo->exec($sql, $_DATA_BIND) ) return 0;
  
  // get results
  if ( !$ResultSet->EOF ) $ROWS = $ResultSet->GetArray();
  else return 0;
  
  $DATA = $ROWS[0];
  if ( $this->debug ) $this->print_d("user [$handle] found in DB: " . print_r($DATA,1));
  
  return $DATA;
}
// END method



// method: push message on to login stack
function _push_login_prompt($message)
{
  if ( in_array($message, $_SESSION[$this->oid]['PROMPT']) ) return;   // no dupes!
  $_SESSION[$this->oid]['PROMPT'][] = $message;
  return;
}
// END method



// method: get login prompt
function _get_login_prompt()
{
  return $_SESSION[$this->oid]['PROMPT'];
}
// END method



// method: dev
function _reset_login_prompt()
{
  unset($_SESSION[$this->oid]['PROMPT']);
  $_SESSION[$this->oid]['PROMPT'] = array();
  return;
}
// END method



// method: push message on to login stack
function _update_status_message($message)
{
  $_SESSION[$this->oid]['status'] = $message;
  return;
}
// END method



// method: push message on to login stack
function _get_status_message()
{
  return $_SESSION[$this->oid]['status'];
}
// END method



// method: push message on to login stack
function _reset_status_message()
{
  $_SESSION[$this->oid]['status'] = '';
  return;
}
// END method



// method: dev
function _dev($prompt)
{
  $this->print_d(__FUNCTION__ . ' in dev');
  $this->print_d("prompt: $prompt", 'silver');
  return;
}
// END method



// method: count login attempts
function _count_login_attempt()
{
  if ( !session_id() ) session_start();
  if ( !isset($_SESSION[$this->oid]['login_attempts']) ) $_SESSION[$this->oid]['login_attempts'] = 1;
  else $_SESSION[$this->oid]['login_attempts']++;
  return;
}
// END method


// method: get login attempts
function _get_login_attempts()
{
  if ( !session_id() ) session_start();
  if ( !isset($_SESSION[$this->oid]['login_attempts']) ) return 0;
  else return $_SESSION[$this->oid]['login_attempts'];
}
// END method


// method: count login attempts
function _reset_login_attempts()
{
  if ( !session_id() ) session_start();
  if ( !isset($_SESSION[$this->oid]['login_attempts']) ) return;
  else $_SESSION[$this->oid]['login_attempts'] = 0;
  return;
}
// END method



// method: reset user
function _reset_user()
{
  if ( $this->debug ) $this->print_d('resetting user data');
  $this->USER = null;
  $_SESSION[$this->oid]['USER'] = null;
  unset($_SESSION[$this->oid]['USER']);
  $this->_set_user_session_data();
  return;
}
// END method


// method: lock out (redirect)
function _lockout()
{
  $this->_update_status_message($this->STATUS_MSG['not_logged_in']);
  trigger_error(__FUNCTION__ . ' in dev', E_USER_WARNING);
  $this->print_d('must add tpl', 'purple');
  print $this->print_r($_SESSION[$this->oid]);
  return;
}
// END method


// method: redirect to login page
function _redirect_to_login()
{
  if ( $this->debug ) $this->print_d('redirecting visitor to login form');
  
  // set gateway (entry point where visitor is returned after successful login
  $this->_set_session_value('gateway', $this->_get_url_self());
  
  // reset user / set nonce
  $this->_reset_user();
  $this->get_login_nonce();  
  
  // if login url !empty, redirect there
  if ( !empty($this->login_url) ) $this->_redirect_to_url($this->login_url);
  
  // else pass to login controller file
  require_once($this->login_ctrl);
  return;
}
// END method



// private: redirect to self
// simplified version of redirect method found in CeoFramework class
function _redirect_to_url($url)
{
  if ( $this->debug ) $this->print_d("redirecting to url [$url]");

  
  // validity check
  if ( !preg_match('%^(http)s?://%i', $url) )
  {
    trigger_error('this method requires an absolute argument (or PHP_SELF) for arg', E_USER_ERROR);
    return 0;
  }
    		
  // close session
  if ( session_id() ) { session_write_close(); }		

  // redirect
  header("Location: $url");
  
  // catch
  $catch = <<<HTML

<h3>You are being redirected to <a href="$url">$url</a></h3>
If you are not redirected, please click the link
  
HTML;

  die($catch);

  return;
}
// END method



// private: reconstructs current url from SERVER values (see comments at http://php.net/reserved.variables)
function _get_url_self()
{
  $url = '';    // return

  // sanity checks
  if ( empty($_SERVER['SERVER_NAME']) ) { trigger_error('server name required', E_USER_ERROR); return 0; }
  
  // set parts
  $http = ( $_SERVER['HTTPS'] != '' ) ? 'https://' : 'http://';
  $host = $_SERVER['SERVER_NAME'];
  $path = $_SERVER['REQUEST_URI'];
  
  // build full url
  $url = $http . $host . $path;
  
  // return
  return $url;
}
// END method



// method: hash (for passwords)
function _hash($string)
{
  $hash = '';
  if ( empty($this->hash_salt) ) trigger_error('prop hash_salt is empty', E_USER_WARNING);
  $hash = md5($this->hash_salt . $string);
  return $hash;
}
// END method



// method: set login nonce
function _set_login_nonce()
{
  $nonce = md5(uniqid(rand(), true));
  $this->_set_session_value($this->nnc_fn, $nonce);
  return;
}
// END method



// method: set login nonce
function _unset_login_nonce()
{
  $this->_unset_session_value($this->nnc_fn);
  $this->_set_session_value('preserve_nonce',0);
  return;
}
// END method


// method: get session data
function _get_user_session_data()
{
  if ( $this->debug ) $this->print_d('getting user SESSION data');

  // initialize session
  if ( !$this->_has_session_data() ) return; 
    
  // retrieve session variables
  $this->USER = $_SESSION[$this->oid]['USER'];
  
  return;
}
// END method


// method: get session data
function _set_user_session_data()
{
  if ( $this->debug ) $this->print_d('saving user data to SESSION');
    
  // retrieve session variables
  $_SESSION[$this->oid]['USER'] = $this->USER;
  
  return;
}
// END method



// method: get session data
function _get_session_value($name)
{
  $value = null;
  
  if ( isset($_SESSION[$this->oid][$name]) ) $value = $_SESSION[$this->oid][$name];
  
  return $value;
}
// END method


// method: _set_session_value
function _set_session_value($name, $value)
{
  // set value 
  $_SESSION[$this->oid][$name] = $value;
  
  return;
}
// END method


// method: unset session value
function _unset_session_value($name)
{
  // set value 
  $_SESSION[$this->oid][$name] = null;
  unset($_SESSION[$this->oid][$name]);
  
  return;
}
// END method


// method: has session data
function _has_session_data()
{
  // retrieve session variables
  if ( empty($_SESSION[$this->oid]) ) return 0;
  else return 1;
}
// END method



// method: get ace codes
function _get_ace_codes()
{
  $if_e_addendum = 'if you believe this to be an error, please contact the site administrator.';
  $is_e_addendum = 'a site administrator has been notified.  please contact an administrator if you have any questions.';

  $_STATUS = array
  (
    'logged_in' => 'you are logged in',
    'not_logged_in' => 'you are not logged in',
  );
  
  $_PROMPT = array
  (
    'protected' => 'you must be logged in to view this page.',
    'session_expired' => 'your session has timed out.  for your security, please log back in.',
    'logged_in' => 'you have been logged in',
    'logged_out' => 'you have been logged out',
    'user_not_found' => 'sorry.  we did not find your account.  please re-enter your login information',
    'pw_not_found' => 'sorry.  we did not find your account.  please re-enter your login information',
  );
  
  $_LOCKOUT = array
  (
    'attempts' => 'sorry. we are unable to log you in with the credentials provided. ' . $if_e_addendum,
    'inactive' => 'your account is not active. ' . $if_e_addendum,
    'level' => 'you are not authorized to see this page. ' . $if_e_addendum,
    'login_error' => 'there was a problem processing your login .' . $is_e_addendum,
    'error' => 'there was a problem with this page. ' . $is_e_addendum,
  );
  
  $this->STATUS_MSG = $_STATUS;
  $this->PROMPT_MSG = $_PROMPT; 
  $this->LOCKOUT_MSG = $_LOCKOUT;
  return;
}
// END method



function _set_filename() { $this->_filename = basename(__FILE__); }
function _set_dirpath() { $this->_dirpath = dirname(__FILE__) . $this->DS; }

} // end class
/*____________________________________________________________________________*/

?>
